import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Between, Like, Repository, IsNull } from 'typeorm';
import WipOrderReport from '@main/entities/service/admin/wip/wip-order-report.entity';
import ProductionOrder from '@main/entities/service/admin/production/production-order.entity';
import SysUser from '@main/entities/service/admin/sys/sys-user.entity';
import BaseShift from '@main/entities/service/admin/base/base-shift.entity';
import BaseMachine from '@main/entities/service/admin/base/base-machine.entity';
import { UtilService } from '@main/shared/services/util.service';
import { SysParamConfigService } from '../../system/paramConfig/paramConfig.service';
import WipShutdownList from '@main/entities/service/admin/wip/wip-shutdown-list.entity';
import { ApiException } from '@main/common/exceptions/api.exception';
import { generateExcelFn } from '@main/excel';
import { SysOperationLogService } from '../../system/operationLog/operationLog.service';
import BaseShiftUser from '@main/entities/service/admin/base/base-shift-user.entity';
import BaseWorkType from '@main/entities/service/admin/base/base-work-type.entity';
import { format } from 'date-fns';
import i18n from '@main/i18n';

@Injectable()
export class WipOrderReportService {
  constructor(
    @InjectRepository(WipOrderReport)
    private orderReportRepository: Repository<WipOrderReport>,
    @InjectRepository(ProductionOrder)
    private orderRepository: Repository<ProductionOrder>,
    @InjectRepository(SysUser) private userRepository: Repository<SysUser>,
    @InjectRepository(BaseShift) private shiftRepository: Repository<BaseShift>,
    @InjectRepository(BaseMachine)
    private machineRepository: Repository<BaseMachine>,
    private paramConfig: SysParamConfigService,
    private util: UtilService,
    @InjectRepository(WipShutdownList)
    private shutdownListRepository: Repository<WipShutdownList>,
    private operationLogService: SysOperationLogService,
    @InjectRepository(BaseShiftUser)
    private shiftUserRepository: Repository<BaseShiftUser>,
    @InjectRepository(BaseWorkType)
    private workTypeRepository: Repository<BaseWorkType>
  ) {}

  async list() {
    return await this.orderReportRepository.find();
  }

  /**
   * 罗列所有配置
   */
  async page(data, languageType) {
    const { pageSize, pageNum, entity = {} } = data;

    const {
      fastSearch,
      reportStatus,
      reportTime,
      machineCode,
      shiftCode,
      materialCode,
      ids = [],
    } = entity;

    const where = {
      orderCode: Like(`%${fastSearch}%`),
      reportCode: Like(`%${fastSearch}%`),
      machineCode: Like(`%${machineCode}%`),
      shiftCode: Like(`%${shiftCode}%`),
      materialCode: Like(`%${materialCode}%`),
      reportFinishStatus: 1,
    };

    if (reportStatus !== '') where['reportStatus'] = reportStatus;

    if (reportTime && reportTime.length) {
      where['reportTime'] = Between(reportTime[0], reportTime[1]);
    }

    if (ids && ids.length) {
      where['id'] = In(ids);
    }

    const langObj = i18n[languageType]['common']['table'];

    const [list, total] = (await this.orderReportRepository.findAndCount({
      where,
      order: {
        updateTime: 'DESC',
      },
      take: pageSize,
      skip: (pageNum - 1) * pageSize,
    })) as any;

    if (list && list.length) {
      for (let i = 0; i < list.length; i++) {
        const { orderCode, shiftCode, reportUserList, machineCode } = list[i];

        const [orderObj, shiftObj, machineObj] = await Promise.all([
          this.orderRepository.findOne({ where: { orderCode } }),
          this.shiftRepository.findOne({ where: { shiftCode } }),
          this.machineRepository.findOne({ where: { machineCode } }),
        ]);

        list[i] = {
          ...list[i],
          ...orderObj,
          id: list[i].id,
        };

        list[i]['shiftName'] = shiftObj.shiftName;

        list[i]['machineName'] = machineObj.machineName;

        const ruList = reportUserList.split(',');

        const idList = [];

        if (ruList && ruList.length) {
          const nickNameList = [];

          for (let j = 0; j < ruList.length; j++) {
            const user = await this.userRepository.findOne({ where: { id: ruList[j] } });

            idList.push(ruList[j]);

            if (user) nickNameList.push(user.nickName);
          }

          list[i]['reportNickNameList'] = nickNameList.join(',');
        }

        list[i].reportUserList = idList as any;
      }
    }

    const newList = await Promise.all(
      list?.map(async (item) => {
        const { reportTime, reportStatus } = item;
        if (reportTime) {
          item.reportTime = format(new Date(reportTime), 'yyyy-MM-dd HH:mm:ss');
        }

        if (reportStatus === 0) {
          item.reportStatus = langObj['unConfirmed'];
        } else if (reportStatus === 1) {
          item.reportStatus = langObj['confirmed'];
        }
        return {
          ...item,
        };
      })
    );

    return [newList, total];
  }

  async export(dto, lang) {
    const [list] = await this.page(dto, lang);

    if (!list || !(list as any).length) {
      throw new ApiException(10052);
    }

    const dataList = list;

    return await generateExcelFn(
      {
        sheetName: 'orderReport',
        mainHeaderList: [
          {
            label: 'reportCode',
          },
          {
            label: 'orderCode',
          },
          {
            label: 'machineName',
          },
          {
            label: 'materialName',
          },
          {
            label: 'version',
          },
          {
            label: 'orderNum',
          },
          {
            label: 'reportNum',
          },
          {
            label: 'reportConfirmNum',
          },
          {
            label: 'goodNum',
          },
          {
            label: 'badNum',
          },
          {
            label: 'shiftName',
          },
          {
            label: 'reportNickNameList',
          },
          {
            label: 'reportTime',
          },
          {
            label: 'reportStatus',
          },
          {
            label: 'remark',
          },
        ],
        dataList,
      },
      lang
    );
  }

  /**
   * 新增
   */
  async add(data, user, mac, ip, syncHostSqlite) {
    const databaseOperationLogList = [];
    const {
      orderCode,
      machineCode,
      reportNum,
      shiftCode,
      userList,
      materialCode,
      materialName,
      version,
      badNum,
      orderStatusCode,
      electricityConsumption: newElectricityConsumption = 0,
      waterConsumption: newWaterConsumption = 0,
      paperPrice = 0,
      paperboardNum = 0,
    } = data;

    // console.log(userList);

    const isAutoConfirmReportWork = await this.paramConfig.findValueByCode(
      'isAutoConfirmReportWork'
    );

    if (orderStatusCode === '30') {
      const reportCode = `BG${this.util.nowDateValue()}${this.util.generateRandomNumberValue(4)}`;

      const result = await this.orderReportRepository.find({ where: { reportCode } });

      if (result && result.length) {
        this.add(data, user, mac, ip, syncHostSqlite);

        return;
      }

      const orderReport = await this.orderReportRepository.insert({
        reportCode,
        orderCode,
        machineCode,
        materialCode,
        materialName,
        version,
        reportNum: 0,
        shiftCode,
        reportUserList: userList.join(','),
        reportStatus: isAutoConfirmReportWork === '1' ? 1 : 0,
        reportFinishStatus: 0,
        reportConfirmNum: isAutoConfirmReportWork === '1' ? 0 : null,
        goodNum: 0,
        badNum: 0,
        electricityConsumption: newElectricityConsumption,
        waterConsumption: newWaterConsumption,
        reportTime: new Date().getTime(),
        createName: user.nickName,
        createUserName: user.userName,
        updateName: user.nickName,
        updateUserName: user.userName,
      });
      databaseOperationLogList.push({
        type: 'add',
        dataType: 'obj',
        database: 'WipOrderReport',
        checkOnlyKeyList: [],
        data: orderReport,
        whereObj: null,
        remark: `WipOrderReport表新增数据`,
      });

      await this.operationLogService.add(
        {
          type: 'add',
          msg: `报工记录管理模块新增报工记录`,
          databaseOperationLogList,
          remark: `新增报工记录${data.reportCode}`,
          mac,
          ip,
          syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
        },
        user
      );
    } else {
      const reportObj = await this.orderReportRepository.findOne({
        where: { orderCode, reportFinishStatus: 0 },
      });

      if (!reportObj) {
        await this.add({ ...data, orderStatusCode: '30' }, user, mac, ip, syncHostSqlite);

        await this.add(data, user, mac, ip, syncHostSqlite);

        return;
      }

      const {
        reportCode,
        electricityConsumption: oldElectricityConsumption,
        waterConsumption: oldWaterConsumption,
        createTime,
      } = reportObj;

      const electricityConsumption = newElectricityConsumption - oldElectricityConsumption;

      const waterConsumption = newWaterConsumption - oldWaterConsumption;

      const electricityPrice: any =
        (await this.paramConfig.findValueByCode('electricityPrice')) || 0;

      const waterPrice: any = (await this.paramConfig.findValueByCode('waterPrice')) || 0;

      const electricityBill = electricityConsumption * electricityPrice;

      const waterBill = waterConsumption * waterPrice;

      const reportTime = new Date().getTime();

      const useTime = reportTime - new Date(createTime).getTime();

      let laborCost = 0;

      const materialCost = paperboardNum * paperPrice;

      await Promise.all(
        userList.map(async (item) => {
          const obj = await this.shiftUserRepository.findOne({
            where: {
              userId: item,
            },
          });

          if (obj) {
            const obj2 = await this.workTypeRepository.findOne({
              where: {
                workTypeCode: obj.workTypeCode,
              },
            });

            if (obj2) {
              const { standardCost = 0 } = obj2;

              if (standardCost) {
                laborCost += Number((standardCost * (useTime / 1000 / 60 / 60)).toFixed(2));
              }
            }
          }
        })
      );

      const inkUsage = 0; // todo

      const variableManufactureCost =
        inkUsage + electricityBill + waterBill + laborCost + materialCost;

      const dataObj = {
        orderCode,
        machineCode,
        materialCode,
        reportNum,
        shiftCode,
        reportUserList: userList.join(','),
        reportStatus: isAutoConfirmReportWork === '1' ? 1 : 0,
        reportFinishStatus: 1,
        reportConfirmNum: isAutoConfirmReportWork === '1' ? reportNum : null,
        goodNum: reportNum - badNum,
        badNum,
        electricityConsumption,
        waterConsumption,
        electricityBill,
        waterBill,
        inkUsage,
        laborCost,
        materialCost,
        variableManufactureCost,
        reportTime,
        updateName: user.nickName,
        updateUserName: user.userName,
      };

      await this.orderReportRepository.update({ reportCode }, dataObj);

      databaseOperationLogList.push({
        type: 'update',
        dataType: 'obj',
        database: 'WipOrderReport',
        checkOnlyKeyList: [],
        data: dataObj,
        whereObj: { reportCode },
        remark: `WipOrderReport表更新报工记录信息`,
      });
      await this.operationLogService.add(
        {
          type: 'update',
          msg: `报工记录管理模块更新报工记录`,
          databaseOperationLogList,
          remark: `更新报工记录${data.reportCode}`,
          mac,
          ip,
          syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
        },
        user
      );

      const shutdownObj = await this.shutdownListRepository.findOne({
        where: { reportCode, shutdownEndTime: IsNull() },
      });

      if (shutdownObj) {
        await this.shutdownListRepository.update(
          { id: shutdownObj.id },
          { shutdownEndTime: new Date().getTime() }
        );
      }
    }
  }

  /**
   * 更新
   */
  async update(data, user, mac, ip, syncHostSqlite) {
    const databaseOperationLogList = [];
    const { id, reportStatus } = data;

    await this.orderReportRepository.update(
      { id },
      { reportStatus, updateName: user.nickName, updateUserName: user.userName }
    );
    databaseOperationLogList.push({
      type: 'update',
      dataType: 'obj',
      database: 'WipOrderReport',
      checkOnlyKeyList: [],
      data: { reportStatus, updateName: user.nickName, updateUserName: user.userName },
      whereObj: { id },
      remark: `WipOrderReport表更新报工记录信息`,
    });
    await this.operationLogService.add(
      {
        type: 'update',
        msg: `报工记录管理模块更新报工记录`,
        databaseOperationLogList,
        remark: `更新报工记录${data.reportCode}`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );
  }

  /**
   * 删除
   */
  async delete(idList, user, mac, ip, syncHostSqlite) {
    const databaseOperationLogList = [];
    await this.orderReportRepository.delete(idList);
    databaseOperationLogList.push({
      type: 'delete',
      dataType: 'array',
      database: 'WipOrderReport',
      checkOnlyKeyList: [],
      data: null,
      whereObj: idList,
      remark: `WipOrderReport表删除报工记录信息`,
    });
    await this.operationLogService.add(
      {
        type: 'delete',
        msg: `报工记录管理模块删除报工记录信息`,
        databaseOperationLogList,
        remark: `删除报工记录信息`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );
  }

  async confirm(data, user, mac, ip, syncHostSqlite) {
    const databaseOperationLogList = [];

    const { reportConfirmNum, shiftCode, userList, id, badNum, remark } = data;

    await this.orderReportRepository.update(
      { id },
      {
        reportConfirmNum,
        shiftCode,
        reportUserList: userList.join(','),
        remark,
        badNum,
        goodNum: reportConfirmNum - badNum,
        reportStatus: 1,
        updateName: user.nickName,
        updateUserName: user.userName,
      }
    );
    databaseOperationLogList.push({
      type: 'update',
      dataType: 'obj',
      database: 'WipOrderReport',
      checkOnlyKeyList: [],
      data: {
        reportConfirmNum,
        shiftCode,
        reportUserList: userList.join(','),
        remark,
        badNum,
        goodNum: reportConfirmNum - badNum,
        reportStatus: 1,
        updateName: user.nickName,
        updateUserName: user.userName,
      },
      whereObj: { id },
      remark: `WipOrderReport表更新报工记录信息`,
    });
    await this.operationLogService.add(
      {
        type: 'update',
        msg: `报工记录管理模块更新报工记录`,
        databaseOperationLogList,
        remark: `更新报工记录${data.reportCode}`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );
  }
}
